package com.net.xpay.admin.controller.admin;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayFundAccountbookQueryResponse;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.net.common.exception.BusinessException;
import com.net.common.model.ResultData;
import com.net.common.model.ResultPagedList;
import com.net.common.util.MoneyUtil;
import com.net.common.util.SerializationUtil;
import com.net.xpay.admin.po.PartnerWithdrawPo;
import com.net.xpay.admin.po.QueryPartnerWithdrawTransPo;
import com.net.xpay.admin.vo.QueryPartnerWithdrawResultVo;
import com.net.xpay.admin.vo.SystemPartnerWithdrawTransAccountVo;
import com.net.xpay.alipay.safePay.PoseidonSafePayAlipayClient;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.domain.partner.PartnerWithdrawRecord;
import com.net.xpay.common.domain.partner.PartnerWithdrawRecordBatch;
import com.net.xpay.common.enums.config.CommonSysConfigKey;
import com.net.xpay.common.enums.partner.WithdrawStatus;
import com.net.xpay.common.helper.CommonSysConfigHelper;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.common.manager.partner.PartnerWithdrawRecordBatchManager;
import com.net.xpay.common.manager.partner.PartnerWithdrawRecordManager;
import com.net.xpay.common.model.search.PartnerWithdrawRecordBatchSearchModel;
import com.net.xpay.common.service.PartnerWithdrawService;
import com.net.xpay.common.validator.AdminPartnerAccountWithdrawValidator;
import com.net.xpay.core.constant.CoreConstant;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.domain.safePay.SafePayBookAccount;
import com.net.xpay.core.domain.safePay.SafePayOrder;
import com.net.xpay.core.manager.safePay.SafePayBookAccountManager;
import com.net.xpay.core.manager.safePay.SafePayOrderManager;
import com.net.xpay.core.model.InnerPayTransBatchModel;
import com.net.xpay.core.model.PayTransModel;
import com.net.xpay.core.service.InnerPayTransService;
import com.net.shard.ShardUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 *

 * 合伙人提现记录
 */
@Slf4j
@RestController
@RequestMapping("/admin/partner-withdraw-record-batch")
@Api(tags = "运营/合伙人批量提现打款记录", description = "运营 合伙人批量提现打款记录 net")
public class AdminPartnerWithdrawRecordBatchController {

    @Autowired
    private PartnerWithdrawRecordBatchManager partnerWithdrawRecordBatchManager;

    @Autowired
    private InnerPayTransService innerPayTransService;

    @Autowired
    private PartnerWithdrawRecordManager partnerWithdrawRecordManager;

    @Autowired
    private CommonSysConfigHelper commonSysConfigHelper;

    @Autowired
    private UserManager userManager;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private PartnerWithdrawService partnerWithdrawService;

    @Autowired
    private AdminPartnerAccountWithdrawValidator adminPartnerAccountWithdrawValidator;

    @Autowired
    private SafePayOrderManager safePayOrderManager;

    @Autowired
    private SafePayBookAccountManager safePayBookAccountManager;

    @Autowired
    private PoseidonSafePayAlipayClient xpaySafePayAlipayClient;


    @ApiOperation("搜索合伙人批量提现打款记录")
    @PostMapping("/search")
    @ResponseBody
    @PreAuthorize("hasAnyRole('ADMIN', 'partner-withdraw-record-batch::search')")
    public ResultPagedList<PartnerWithdrawRecordBatch> searchPartnerWithdrawRecord(@RequestBody PartnerWithdrawRecordBatchSearchModel searchModel) {
        searchModel.setIsOffline(1);
        List<PartnerWithdrawRecordBatch> records = partnerWithdrawRecordBatchManager.search(searchModel);
        long count = partnerWithdrawRecordBatchManager.searchCount(searchModel);
        return new ResultPagedList<>(records, count, searchModel);
    }

    @ApiOperation("取消转账")
    @PostMapping("/cancel")
    @PreAuthorize("hasAnyRole('ADMIN')")
    public ResultData<Boolean> cancelTransMoney(Long id) {
        Preconditions.checkArgument(id != null);

        PartnerWithdrawRecordBatch batch = partnerWithdrawRecordBatchManager.getById(id);

        if (WithdrawStatus.PAYED.equals(batch.getStatus())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "转账已完成，请勿重复转账");
        }

        batch.setStatus(WithdrawStatus.FAILED);
        batch.setEndTime(LocalDateTime.now());
        partnerWithdrawRecordBatchManager.updateByPrimaryKeyWithVersion(batch);
        return new ResultData<>(true);
    }

    @ApiOperation("手动生成转账批次")
    @PostMapping("/create")
    @PreAuthorize("hasAnyRole('ADMIN', 'partner-withdraw-record-batch::create')")
    public ResultData<PartnerWithdrawRecordBatch> createTransBatch(@RequestBody PartnerWithdrawPo withdrawPo) {
        Preconditions.checkArgument(withdrawPo != null && withdrawPo.getPartnerId() != null && withdrawPo.getTransferMoney() != null);

        log.info("createTransBatch params={}", SerializationUtil.obj2String(withdrawPo));

        if (withdrawPo.getTransferMoney() < CoreConstant.PARTNER_WITHDRAW_MIN_MONEY) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "提现至少满1毛");
        }
        if (withdrawPo.getIsOffline() == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请选择打款方式");
        }

        //提现前先检查下安全发记账本是否还有余额
        if (withdrawPo.getIsOffline() == 0) {
            adminPartnerAccountWithdrawValidator.validateSafePayAccountEnough(MoneyUtil.convertCentToBigDecimal(withdrawPo.getTransferMoney(), 2));
        }

        PartnerWithdrawRecord record = partnerWithdrawService.createPartnerWithdrawRecord(withdrawPo.getPartnerId(), withdrawPo.getTransferMoney(), withdrawPo.getAlipayName(), withdrawPo.getAlipayAccount());
        //生成提现批次
        PartnerWithdrawRecordBatch recordBatch = PartnerWithdrawRecordBatch.getInstance();
        recordBatch.setStatus(WithdrawStatus.WAIT_PAY);
        //现在默认安全发自动转账
        recordBatch.setIsOffline(withdrawPo.getIsOffline());
        recordBatch.setTotalNum(1);
        recordBatch.setTotalMoney(record.getTransferMoney());
        recordBatch.setWithdrawRecordIds(Lists.newArrayList(record.getId()));
        partnerWithdrawRecordBatchManager.save(recordBatch);

        return new ResultData<>(recordBatch);
    }


    @ApiOperation("查询合伙人提现打款账号")
    @PostMapping("/query-partner-withdraw-safe-pay-account")
    public ResultData<SystemPartnerWithdrawTransAccountVo> querySystemPartnerWithdrawTransAccount() {
        SystemPartnerWithdrawTransAccountVo vo = new SystemPartnerWithdrawTransAccountVo();

        //打款支付宝和打款手机号
        String alipayAccount = commonSysConfigHelper.getString(CommonSysConfigKey.PARTNER_WITHDRAW_SAFE_PAY_ACCOUNT);
        String sysMobile = commonSysConfigHelper.getString(CommonSysConfigKey.PARTNER_WITHDRAW_MOBILE);
        if (Strings.isNullOrEmpty(alipayAccount) || Strings.isNullOrEmpty(sysMobile)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请配置系统安全发打款账号");
        }

        User transUser = userManager.findByMobile(sysMobile);
        UserShard shard = userShardManager.getById(transUser.getId());
        vo.setAlipayNickName(alipayAccount);
        vo.setUserId(transUser.getId());
        //失败了
        try {
            ShardUtil.setShardContext(shard.getShardId());
            SafePayBookAccount safePayBookAccount = safePayBookAccountManager.findByAlipayNickName(transUser.getId(), alipayAccount);
            vo.setSafePayBookAccountId(safePayBookAccount.getId());
            AlipayFundAccountbookQueryResponse resp;
            try {
                resp = xpaySafePayAlipayClient.queryAlipayFundAccountbook(safePayBookAccount.getBookId(), safePayBookAccount.getAgreementNo());

                if (resp.isSuccess()) {
                    String availableAmount = resp.getAvailableAmount();
                    vo.setBookBalance(availableAmount);
                } else {
                    throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, alipayAccount + "转账方余额查询失败：" + resp.getMsg() + "|" + resp.getSubMsg());
                }
            } catch (AlipayApiException e) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "查询安全发记账本异常");
            }
            return new ResultData<>(vo);
        } finally {
            ShardUtil.cleanShardContext();
        }
    }

    @ApiOperation("单笔查询转账结果")
    @PostMapping("/query-single-trans-result")
    public ResultData<QueryPartnerWithdrawResultVo> queryPartnerWithdrawTransStatus(@RequestBody QueryPartnerWithdrawTransPo po) {
        Preconditions.checkArgument(po != null && po.getPartnerWithdrawRecordBatchId() != null);
        QueryPartnerWithdrawResultVo vo = new QueryPartnerWithdrawResultVo();

        PartnerWithdrawRecordBatch batch = partnerWithdrawRecordBatchManager.getById(po.getPartnerWithdrawRecordBatchId());
        Long withdrawRecordId = batch.getWithdrawRecordIds().get(0);
        PartnerWithdrawRecord withdrawRecord = partnerWithdrawRecordManager.getById(withdrawRecordId);

        vo.setPartnerWithdrawRecordBatchId(po.getPartnerWithdrawRecordBatchId());
        vo.setPartnerWithdrawRecordId(withdrawRecordId);
        vo.setStatus(withdrawRecord.getStatus());
        vo.setDealing(true);
        if (withdrawRecord.getStatus() != WithdrawStatus.FAILED && withdrawRecord.getStatus() != WithdrawStatus.PAYED) {
            return new ResultData<>(vo);
        }
        vo.setDealing(false);
        if (withdrawRecord.getStatus() == WithdrawStatus.PAYED) {
            return new ResultData<>(vo);
        }

        //打款支付宝和打款手机号
        String alipayAccount = commonSysConfigHelper.getString(CommonSysConfigKey.PARTNER_WITHDRAW_SAFE_PAY_ACCOUNT);
        String sysMobile = commonSysConfigHelper.getString(CommonSysConfigKey.PARTNER_WITHDRAW_MOBILE);
        if (Strings.isNullOrEmpty(alipayAccount) || Strings.isNullOrEmpty(sysMobile)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请配置系统安全发打款账号");
        }
        User transUser = userManager.findByMobile(sysMobile);
        UserShard shard = userShardManager.getById(transUser.getId());

        //失败了
        try {
            ShardUtil.setShardContext(shard.getShardId());

            SafePayOrder safePayOrder = safePayOrderManager.findByImportBizNo(transUser.getId(), batch.getBizId(), withdrawRecord.getId().toString());
            vo.setErrorCode(safePayOrder.getErrorCode());
            vo.setErrorMsg(safePayOrder.getErrorMsg());
            return new ResultData<>(vo);
        } finally {
            ShardUtil.cleanShardContext();
        }
    }


    @ApiOperation("转账")
    @PostMapping("/trans")
    @PreAuthorize("hasAnyRole('ADMIN', 'partner-withdraw-record-batch::trans')")
    public ResultData<String> transMoney(Long id, Integer ignoreErrorAccount) {
        Preconditions.checkArgument(id != null && ignoreErrorAccount != null);

        PartnerWithdrawRecordBatch batch = partnerWithdrawRecordBatchManager.getById(id);
        if (!Strings.isNullOrEmpty(batch.getLastPayUrl())) {
            return new ResultData<>(batch.getLastPayUrl());
        }

        if (WithdrawStatus.PAYED.equals(batch.getStatus())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "转账已完成，请勿重复转账");
        }

        //打款支付宝和打款手机号
        String alipayAccount = commonSysConfigHelper.getString(CommonSysConfigKey.PARTNER_WITHDRAW_ALIPAY_ACCOUNT);
        String sysMobile = commonSysConfigHelper.getString(CommonSysConfigKey.PARTNER_WITHDRAW_MOBILE);
        if (Strings.isNullOrEmpty(alipayAccount) || Strings.isNullOrEmpty(sysMobile)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请配置系统打款账号");
        }

        User transUser = userManager.findByMobile(sysMobile);
        if (transUser == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "系统打款账号不存在");
        }
        UserShard shard = userShardManager.getById(transUser.getId());
        String payUrl;
        try {
            ShardUtil.setShardContext(shard.getShardId());
            payUrl = doTransMoney(batch, alipayAccount, sysMobile, ignoreErrorAccount);
        } finally {
            ShardUtil.cleanShardContext();
        }

        return new ResultData<>(payUrl);
    }

    @ApiOperation("银行转账")
    @PostMapping("/ensure")
    @PreAuthorize("hasAnyRole('ADMIN', 'partner-withdraw-record-batch::ensure-trans')")
    public ResultData<Boolean> ensurePartnerWithdrawBatch(Long id) {
        Preconditions.checkArgument(id != null);

        partnerWithdrawService.ensurePartnerWithdrawBatch(id);

        return new ResultData<>(true);
    }


    private String doTransMoney(PartnerWithdrawRecordBatch batch, String alipayAccount, String sysMobile, Integer ignoreErrorAccount) {
        List<Long> withdrawRecordIds = batch.getWithdrawRecordIds();
        Preconditions.checkArgument(CollectionUtils.isNotEmpty(withdrawRecordIds));
        List<PartnerWithdrawRecord> withdrawRecords = partnerWithdrawRecordManager.listByIds(withdrawRecordIds);

        InnerPayTransBatchModel payTransBatchModel = new InnerPayTransBatchModel();
        payTransBatchModel.setAlipayNickName(alipayAccount);
        payTransBatchModel.setMobile(sysMobile);
        payTransBatchModel.setIgnoreErrorAccount(ignoreErrorAccount);
        payTransBatchModel.setImportBatchNo(batch.getBizId());
        List<PayTransModel> payTrans = new ArrayList<>();
        for (PartnerWithdrawRecord withdrawRecord : withdrawRecords) {
            if (withdrawRecord.getStatus() == WithdrawStatus.FAILED) {
                continue;
            }
            PayTransModel payTransModel = new PayTransModel();
            payTransModel.setImportBizNo(withdrawRecord.getId().toString());
            payTransModel.setTransAmount(MoneyUtil.convertCentToString(withdrawRecord.getTransferMoney(), 2));
            payTransModel.setRemark("提现");
            payTransModel.setIdentity(withdrawRecord.getAlipayAccount());
            payTransModel.setName(withdrawRecord.getAlipayName());
            payTrans.add(payTransModel);
        }
        payTransBatchModel.setPayTrans(payTrans);
        String payUrl = innerPayTransService.batchPayTrans(payTransBatchModel);
        if (!Strings.isNullOrEmpty(payUrl)) {
            batch.setStatus(WithdrawStatus.DEALING);
            batch.setDealingTime(LocalDateTime.now());
            batch.setLastPayUrl(payUrl);
            partnerWithdrawRecordBatchManager.updateByPrimaryKeyWithVersion(batch);
        }
        return payUrl;
    }
}
